﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace Code4WP7SDK.Controls
{
    public class CoverFlowPanel : Panel
    {
        #region Dependency Properties
        [Category("CoverFlowPanel")]
        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public IEasingFunction AnimationFunction
        {
            get { return (IEasingFunction)GetValue(AnimationFunctionProperty); }
            set { SetValue(AnimationFunctionProperty, value); }
        }

        public static readonly DependencyProperty AnimationFunctionProperty =
            DependencyProperty.Register("AnimationFunction", typeof(IEasingFunction), typeof(CoverFlowPanel), null);

        [Category("CoverFlowPanel")]
        public TimeSpan AnimationDuration
        {
            get { return (TimeSpan)GetValue(AnimationDurationProperty); }
            set { SetValue(AnimationDurationProperty, value); }
        }

        public static readonly DependencyProperty AnimationDurationProperty =
            DependencyProperty.Register("AnimationDuration", typeof(TimeSpan), typeof(CoverFlowPanel),null);

        [Category("CoverFlowPanel")]
        public double ItemWidth
        {
            get { return (double)GetValue(ItemWidthProperty); }
            set { SetValue(ItemWidthProperty, value); }
        }

        public static readonly DependencyProperty ItemWidthProperty =
            DependencyProperty.Register("ItemWidth", typeof(double), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public double ItemHeight
        {
            get { return (double)GetValue(MyPropertyProperty); }
            set { SetValue(MyPropertyProperty, value); }
        }

        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.Register("ItemHeight", typeof(double), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public double ItemRelativeSize
        {
            get { return (double)GetValue(ItemRelativeSizeProperty); }
            set { SetValue(ItemRelativeSizeProperty, value); }
        }

        public static readonly DependencyProperty ItemRelativeSizeProperty =
            DependencyProperty.Register("ItemRelativeSize", typeof(double), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public bool UseRelativeSize
        {
            get { return (bool)GetValue(UseRelativeSizeProperty); }
            set { SetValue(UseRelativeSizeProperty, value); }
        }

        public static readonly DependencyProperty UseRelativeSizeProperty =
            DependencyProperty.Register("UseRelativeSize", typeof(bool), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public int ItemVisibility
        {
            get { return (int)GetValue(ItemVisibilityProperty); }
            set { SetValue(ItemVisibilityProperty, value); }
        }

        public static readonly DependencyProperty ItemVisibilityProperty =
            DependencyProperty.Register("ItemVisibility", typeof(int), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public double ItemFading
        {
            get { return (double)GetValue(ItemFadingProperty); }
            set { SetValue(ItemFadingProperty, value); }
        }

        public static readonly DependencyProperty ItemFadingProperty =
            DependencyProperty.Register("ItemFading", typeof(double), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public double FocusItemDistance
        {
            get { return (double)GetValue(FocusItemDistanceProperty); }
            set { SetValue(FocusItemDistanceProperty, value); }
        }

        public static readonly DependencyProperty FocusItemDistanceProperty =
            DependencyProperty.Register("FocusItemDistance", typeof(double), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));


        [Category("CoverFlowPanel")]
        public double UnFocusItemDistance
        {
            get { return (double)GetValue(UnFocusItemDistanceProperty); }
            set { SetValue(UnFocusItemDistanceProperty, value); }
        }

        public static readonly DependencyProperty UnFocusItemDistanceProperty =
            DependencyProperty.Register("UnFocusItemDistance", typeof(double), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public double FocusItemOffSet
        {
            get { return (double)GetValue(FocusItemOffSetProperty); }
            set { SetValue(FocusItemOffSetProperty, value); }
        }

        public static readonly DependencyProperty FocusItemOffSetProperty =
            DependencyProperty.Register("FocusItemOffSet", typeof(double), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public double UnFocusItemOffSet
        {
            get { return (double)GetValue(UnFocusItemOffSetProperty); }
            set { SetValue(UnFocusItemOffSetProperty, value); }
        }

        public static readonly DependencyProperty UnFocusItemOffSetProperty =
            DependencyProperty.Register("UnFocusItemOffSet", typeof(double), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public double FocusItemAngle
        {
            get { return (double)GetValue(FocusItemAngleProperty); }
            set { SetValue(FocusItemAngleProperty, value); }
        }

        public static readonly DependencyProperty FocusItemAngleProperty =
            DependencyProperty.Register("FocusItemAngle", typeof(double), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public double UnFocusItemAngle
        {
            get { return (double)GetValue(UnFocusItemAngleProperty); }
            set { SetValue(UnFocusItemAngleProperty, value); }
        }

        public static readonly DependencyProperty UnFocusItemAngleProperty =
            DependencyProperty.Register("UnFocusItemAngle", typeof(double), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        [Category("CoverFlowPanel")]
        public int FocusItemIndex
        {
            get { return (int)GetValue(FocusItemIndexProperty); }
            set { SetValue(FocusItemIndexProperty, value); }
        }

        public static readonly DependencyProperty FocusItemIndexProperty =
            DependencyProperty.Register("FocusItemIndex", typeof(int), typeof(CoverFlowPanel), new PropertyMetadata(PropertyChanged));

        #endregion

        #region Constructor
        public CoverFlowPanel()
        {
            Orientation = Orientation.Horizontal;

            AnimationFunction = new CubicEase { EasingMode = EasingMode.EaseOut };
            AnimationDuration = TimeSpan.FromSeconds(0.4);

            ItemWidth = 100;
            ItemHeight = 100;
            ItemRelativeSize = 0.8;
            UseRelativeSize = false;

            ItemFading = 0.2;
            ItemVisibility = 3;

            FocusItemDistance = 0;
            UnFocusItemDistance = 200;
            FocusItemOffSet = 50;
            UnFocusItemOffSet = 10;
            FocusItemAngle = 0;
            UnFocusItemAngle = 45;

            FocusItemIndex = -1;
        }
        #endregion

        public static void PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            CoverFlowPanel coverFlowPanel = (CoverFlowPanel)obj;
            coverFlowPanel.InvalidateArrange();
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            foreach (FrameworkElement child in Children)
            {
                if (child.RenderTransform.GetType() != typeof(TranslateTransform))
                {
                    child.RenderTransform = new TranslateTransform();
                }
                if (child.Projection == null)
                {
                    child.Projection = new PlaneProjection();
                }
                child.Measure(availableSize);
            }
            return base.MeasureOverride(availableSize);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            double isw = ItemWidth;
            double ish = ItemHeight;

            if (UseRelativeSize) //如果根据父控件来判断大小
            {
                if (Orientation == Orientation.Horizontal)
                {
                    //如果是水平方向排列则需要高度等于宽度都等于当前手机宽度
                    isw = ish = finalSize.Width * ItemRelativeSize;
                }
                else
                {
                    //如果是竖直方向排列则需要高度等于宽度都等于当前手机高度
                    isw = ish = finalSize.Height * ItemRelativeSize;
                }
            }

            Point center = new Point((finalSize.Width - isw) / 2, (finalSize.Height - ish) / 2);
            //添加动画
            for (int i = 0; i < Children.Count; i++)
            {
                FrameworkElement child = (FrameworkElement)Children[i];
                child.Width = isw;
                child.Height = ish;
                child.Arrange(new Rect(center.X, center.Y, isw, ish));

                Storyboard sb = new Storyboard();

                double dist = i - FocusItemIndex;
                double disti = Math.Abs(dist);
                //设置Z轴
                Canvas.SetZIndex(child, -(int)disti); 
                //设置translatetransform动画
                TranslateTransform translateTransform = (TranslateTransform)child.RenderTransform;
                DoubleAnimation transaim = new DoubleAnimation() { EasingFunction = this.AnimationFunction, Duration = this.AnimationDuration };
                Storyboard.SetTarget(transaim, translateTransform);
                if (Orientation == Orientation.Vertical)
                {
                    Storyboard.SetTargetProperty(transaim, new PropertyPath(TranslateTransform.YProperty));
                }
                else
                {
                    Storyboard.SetTargetProperty(transaim, new PropertyPath(TranslateTransform.XProperty));
                }
                transaim.To = disti > 1 ? (dist < 0 ? -FocusItemOffSet : FocusItemOffSet) + dist * UnFocusItemOffSet : dist * FocusItemOffSet;
                //设置PlaneProjection动画
                PlaneProjection projection = (PlaneProjection)child.Projection;
                DoubleAnimation proaim = new DoubleAnimation() { EasingFunction = this.AnimationFunction, Duration = this.AnimationDuration };
                Storyboard.SetTarget(proaim, projection);
                Storyboard.SetTargetProperty(proaim, new PropertyPath(PlaneProjection.GlobalOffsetZProperty));
                DoubleAnimation proaim2 = new DoubleAnimation() { EasingFunction = this.AnimationFunction, Duration = this.AnimationDuration };
                Storyboard.SetTarget(proaim2, projection);

                if (dist != 0)
                {
                    proaim.To = -disti * UnFocusItemDistance;
                    if (Orientation == Orientation.Vertical)
                    {
                        Storyboard.SetTargetProperty(proaim2, new PropertyPath(PlaneProjection.RotationXProperty));
                    }
                    else
                    {
                        Storyboard.SetTargetProperty(proaim2, new PropertyPath(PlaneProjection.RotationYProperty));
                    }
                    proaim2.To = dist < 0 ? -UnFocusItemAngle : UnFocusItemAngle;
                }
                else
                {
                    proaim.To = FocusItemDistance;
                    if (Orientation == Orientation.Vertical)
                    {
                        Storyboard.SetTargetProperty(proaim2, new PropertyPath(PlaneProjection.RotationXProperty));
                    }
                    else
                    {
                        Storyboard.SetTargetProperty(proaim2, new PropertyPath(PlaneProjection.RotationYProperty));
                    }
                    proaim2.To = FocusItemAngle;
                }

                DoubleAnimation fanim = new DoubleAnimation() { EasingFunction = this.AnimationFunction, Duration = this.AnimationDuration };
                Storyboard.SetTarget(fanim, child);
                Storyboard.SetTargetProperty(fanim, new PropertyPath(FrameworkElement.OpacityProperty));

                if (disti > ItemVisibility)
                {
                    fanim.To = 0.0;
                }
                else
                {
                    fanim.To = Math.Max(0.0, 1.0 - disti * ItemFading);
                }

                sb.Children.Add(transaim);
                sb.Children.Add(proaim);
                sb.Children.Add(proaim2);
                sb.Children.Add(fanim);
                sb.Begin();
            }
            return base.ArrangeOverride(finalSize);
        }
    }
}
